/**
 * 分页列表组件
 *
 */
import {
  useState,
  useEffect,
  useRef,
  memo,
  forwardRef,
  useImperativeHandle,
} from "react";
import { ScrollView, View } from "@tarojs/components";
import { Loading } from "@nutui/nutui-react-taro";
import cn from "classnames";
import { useDebounceFn } from "@taro-hooks/ahooks";
import { instance as Log } from "@/lib/log";
import { Top } from "@nutui/icons-react-taro";

interface Props {
  id?: string;
  rowkey?: string;
  api: any;
  Item: any;
  headerHeight?: any;
  layoutRef?: any;
  params?: any;
  className?: string;
  slotHeader?: any;
  itemProps?: any;
  itemClassGroup?: string;
  styles?: any;
  loadingSlot?: any;
}

const List = (
  {
    id = "TaroScrollViewList",
    rowkey = "id",
    api,
    Item,
    layoutRef,
    params = {},
    className,
    slotHeader,
    itemProps = {},
    itemClassGroup = "",
    styles,
    loadingSlot,
  }: Props,
  ref
) => {
  const [dataSource, setDataSource] = useState([]);
  const [loading, setLoading] = useState(true);
  const [isLoaded, setLoaded] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [refresherTriggered, setRefresherTriggered] = useState(false);
  const [scrollIntoViewId, setscrollIntoViewId] = useState<string>();
  const [backTopOpen, setBackTopOpen] = useState<boolean>(false);
  const pageNo = useRef(1);
  const [pageSize] = useState(20);
  const _freshing = useRef(false);
  const _componentRef = useRef<any>();
  const _componentHeight = useRef<any>();
  const _isDone = useRef(true);

  useImperativeHandle(ref, () => ({
    reload() {
      init();
    },
  }));

  useEffect(() => {
    init();
  }, []);

  /**
   * 获取数据
   * @param {}
   * @return
   */
  const getData = (reload, options?: any) => {
    // Log.log("分页列表接口请求:options", options);
    _isDone.current = false;
    if (reload) {
      setLoaded(false);
      pageNo.current = 1;
    } else {
      pageNo.current += 1;
    }
    return api({
      current: pageNo.current,
      pageSize,
      ...params,
    })
      .then((res) => {
        const { data }: any = res || {};
        const { total } = data || {};
        const list = data.list || [];
        if (reload) {
          setDataSource(list);
          if (total === list.length) {
            setHasMore(false);
          } else {
            setHasMore(true);
          }
        } else {
          const newData = dataSource.concat(list);
          setDataSource(newData);
          if (total === newData.length) {
            setHasMore(false);
          } else {
            setHasMore(true);
          }
        }
      })
      .catch((e) => {
        if (reload) {
          pageNo.current = 0;
        } else {
          pageNo.current -= 1;
        }
        layoutRef?.current?.setServiceError(true, e?.msg);
      })
      .finally(() => {
        setLoading(false);
        setLoaded(true);
        setTimeout(() => {
          _isDone.current = true;
        }, 200);
      });
  };

  const loadMore = () => {
    if (hasMore) {
      getData(false);
    }
  };

  const refresh = () => {
    if (_freshing.current) return;
    _freshing.current = true;
    setRefresherTriggered(true);
    getData(true).finally(() => {
      setTimeout(() => {
        _freshing.current = false;
        setRefresherTriggered(false);
      }, 500);
    });
    return true;
  };

  const init = () => {
    getData(true).finally(() => {
      getComponentHeight();
    });
  };

  /**
   * 解决滚动条触底不刷新问题
   * @param {}
   * @return
   */
  const handleScroll = ({ detail: { scrollTop, scrollHeight } }) => {
    if (scrollTop > 1500) {
      setBackTopOpen(true);
    } else {
      setBackTopOpen(false);
      setscrollIntoViewId("");
    }
    // Log.log(JSON.stringify({ scrollTop, scrollHeight }));
    // Log.log(
    //   _componentHeight.current.height +
    //     "_" +
    //     _componentHeight.current.lowerThreshold
    // );
    // Log.log(
    //   _componentHeight.current.height + scrollTop >
    //     scrollHeight - _componentHeight.current.lowerThreshold
    // );
    // Log.log(_isDone.current);
    if (
      _componentHeight.current.height + scrollTop >
      scrollHeight - _componentHeight.current.lowerThreshold
    ) {
      setTimeout(() => {
        if (_isDone.current) {
          if (hasMore) {
            getData(false, { isEmitScroll: true });
          }
        }
      }, 100);
    }
  };
  const { run: handleScrollDebounceFn, cancel: handleScrollDebounceCannel } =
    useDebounceFn(handleScroll, {
      wait: 100,
    });
  /**
   * 获取组件高度
   * @param {}
   * @return
   */
  const getComponentHeight = () => {
    if (process.env.TARO_ENV === "weapp") {
      setTimeout(() => {
        wx.createSelectorQuery()
          .select(`#${id}_componentRef`)
          .boundingClientRect((rect) => {
            if (rect) {
              _componentHeight.current = {
                height: rect.height,
                lowerThreshold: rect.height * 0.25,
              };
            }
          })
          .exec();
      });
    } else if (process.env.TARO_ENV === "h5") {
      _componentHeight.current = {
        height: _componentRef?.current?.offsetHeight,
        lowerThreshold: _componentRef?.current?.offsetHeight * 0.25,
      };
    }
  };

  /**
   * 返回顶部
   * @param {}
   * @return
   */
  const handleBackTop = () => {
    setscrollIntoViewId(`${id}_top`);
  };

  return loading ? (
    <View
      ref={_componentRef}
      id={`${id}_componentRef`}
      className={`relative w-full flex-1 ${loadingSlot ? "" : "flex items-center justify-center"
        }`}
    >
      {loadingSlot || <Loading />}
    </View>
  ) : (
    <View
      className={cn(className, "relative w-full flex-1 flex")}
      style={styles}
    >
      <ScrollView
        className="absolute left-0 right-0 top-0 bottom-0 overflow-auto"
        scrollY
        scrollWithAnimation
        lowerThreshold={50}
        refresherTriggered={refresherTriggered}
        onScrollToLower={loadMore}
        onScroll={handleScrollDebounceFn}
        scrollIntoView={scrollIntoViewId}
        refresherEnabled
        onRefresherRefresh={refresh}
      >
        <View id={`${id}_top`}></View>
        {dataSource && dataSource.length > 0 ? (
          <>
            {slotHeader}
            <View className={cn(itemClassGroup, "clearfix")}>
              {dataSource?.map((item: any) => (
                <Item
                  key={item[rowkey]}
                  data={item}
                  {...itemProps}
                  reload={() => getData(true)}
                />
              ))}
            </View>
            <View className="text-center py-[20rpx] text-[28rpx] text-[#999]">
              {!hasMore ? "没有更多了" : "加载中..."}
            </View>
          </>
        ) : (
          isLoaded && (
            <View>
              {slotHeader}
              没有数据
            </View>
          )
        )}
      </ScrollView>
      <View
        onClick={handleBackTop}
        style={{
          opacity: backTopOpen ? 0.7 : 0,
          zIndex: backTopOpen ? 1 : -1,
          transition: ".5s",
        }}
        className="fixed from-transparent right-[30rpx] z-90 top-[80vh] border-[2rpx] border-[#eee] border-solid rounded-full bg-white w-[60rpx] h-[60rpx] flex justify-center items-center"
      >
        <Top size="10"></Top>
      </View>
    </View>
  );
};
export default memo(forwardRef(List));
